1
|
|
|
var SDK = require('@ama-team/voxengine-sdk') |
2
|
|
|
var TimeoutException = SDK.Concurrent.TimeoutException |
3
|
|
|
var timeout = SDK.Concurrent.timeout |
4
|
|
|
var CancellationToken = SDK.Concurrent.CancellationToken |
5
|
|
|
var Slf4j = require('@ama-team/voxengine-sdk').Logger.Slf4j |
6
|
|
|
var Objects = require('../Utility').Objects |
7
|
|
|
|
8
|
|
|
/** |
9
|
|
|
* @class |
10
|
|
|
* |
11
|
|
|
* @implements {IExecutor} |
12
|
|
|
* |
13
|
|
|
* @param {IExecutionContext} ctx |
14
|
|
|
* @param {object} [options] |
15
|
|
|
*/ |
16
|
|
|
function Executor (ctx, options) { |
17
|
|
|
var self = this |
18
|
|
|
options = options || {} |
19
|
|
|
var logger = Slf4j.factory(options.logger, 'ama-team.vsf.execution.executor') |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* @inheritDoc |
23
|
|
|
*/ |
24
|
|
|
this.execute = function (fn, args) { |
25
|
|
|
return fn.apply(ctx, args || []) |
26
|
|
|
} |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* @inheritDoc |
30
|
|
|
*/ |
31
|
|
|
this.promise = function (fn, args) { |
32
|
|
|
try { |
33
|
|
|
return Promise.resolve(self.execute(fn, args)) |
34
|
|
|
} catch (e) { |
35
|
|
|
return Promise.reject(e) |
36
|
|
|
} |
37
|
|
|
} |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* @param {THandler} handler |
41
|
|
|
* @param {CancellationToken} [parent] |
42
|
|
|
*/ |
43
|
|
|
function tokenFactory (handler, parent) { |
44
|
|
|
var deps = parent ? [parent] : [] |
45
|
|
|
return new CancellationToken(deps, 'handler `' + handler.id + '`') |
46
|
|
|
} |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* @param {THandler} handler |
50
|
|
|
* @param {CancellationToken} [token] |
51
|
|
|
* @param {*[]} [args] |
52
|
|
|
* @param {number} tokenArg |
53
|
|
|
* @return {Function} |
54
|
|
|
*/ |
55
|
|
|
function callbackFactory (handler, args, token, tokenArg) { |
56
|
|
|
return function (resolve, reject) { |
57
|
|
|
var message = 'Handler `' + handler.id + '` has exceeded it\'s timeout ' + |
58
|
|
|
'of ' + handler.timeout + ' ms' |
59
|
|
|
logger.warn(message) |
60
|
|
|
var error = new TimeoutException(message) |
61
|
|
|
args[tokenArg].cancel() |
62
|
|
|
if (!Objects.isObject(handler.onTimeout) || !Objects.isFunction(handler.onTimeout.handler)) { |
63
|
|
|
return reject(error) |
64
|
|
|
} |
65
|
|
|
args = args.slice().concat(error) |
66
|
|
|
return self |
67
|
|
|
.runHandler(handler.onTimeout, args, token, tokenArg) |
68
|
|
|
.then(resolve, function (e) { reject(e) }) |
69
|
|
|
} |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* @inheritDoc |
74
|
|
|
*/ |
75
|
|
|
this.runHandler = function (handler, args, token, tokenArg) { |
76
|
|
|
logger.debug('Running handler `{}`', handler.id) |
77
|
|
|
args = args ? args.slice() : [] |
78
|
|
|
tokenArg = typeof tokenArg === 'number' ? tokenArg : args.length |
79
|
|
|
args[tokenArg] = tokenFactory(handler, token) |
80
|
|
|
var promise = self.promise(handler.handler, args) |
81
|
|
|
if (typeof handler.timeout === 'number' && handler.timeout >= 0) { |
82
|
|
|
logger.trace('Scheduling handler `{}` timeout in {} ms', handler.id, |
83
|
|
|
handler.timeout) |
84
|
|
|
var message = handler.id + ' has exceeded it\'s execution timeout of ' + |
85
|
|
|
handler.timeout |
86
|
|
|
var callback = callbackFactory(handler, args, token, tokenArg) |
87
|
|
|
promise = timeout(promise, handler.timeout, callback, message) |
88
|
|
|
} |
89
|
|
|
return promise |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
this.getContext = function () { |
93
|
|
|
return ctx |
94
|
|
|
} |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
module.exports = { |
98
|
|
|
Executor: Executor |
99
|
|
|
} |
100
|
|
|
|